//-WinterFramework ? WinterFeather
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

public class AssetBundleManager : SingleMono<AssetBundleManager>
{
    readonly string CONFIG_FILEHEAD = "configFileHead.txt";
    readonly string BUNDLE_FILEHEAD = "bundlesFlieHead.txt";
    public readonly string BUNDLES_FOLDERNAME = "Bundles";
    public readonly string CONFIG_FOLDERNAME = "ConfigTables";
    public readonly string SCRIPT_FOLDERNAME = "Scripts";

    //public AssetBundle bullectBundle, monsterBundle,iconBundle;
    string REMOTE_PATH;
    string TEST_REMOTE_PATH;
    string SIMULATE_REMOTE_PATH;
    string LOCAL_PATH;

    public readonly string UI_BUNDLE = "uipanel";//UI 
    public readonly string SOUND_BUNDLE = "sound";//UI 
    public readonly string SCENE_BUNDLE = "scene";
    // //public readonly string COMMON_BUNDLE = "common_bundle";//ͨ��
    // public readonly string POOL_BUNDLE = "pool_bundle";//
  
    // public readonly string FIXED_UI_BUNDLE = "fixed_ui_bundle";//���Bundle

    AssetsDownloadEnv assetsDownloadEnv = AssetsDownloadEnv.Testing;

    public Dictionary<string, AssetBundle> bundles;
    void InitPath()
    {
        REMOTE_PATH = Application.streamingAssetsPath;///"http://localhost/LRS/";////
        TEST_REMOTE_PATH = Application.streamingAssetsPath; ///"http://localhost/LRS/";
        SIMULATE_REMOTE_PATH = Application.streamingAssetsPath;
        LOCAL_PATH = Application.persistentDataPath;
    }
    public void SetPath(int id, string path)
    {
        switch (id)
        {
            case 0:
                REMOTE_PATH = path; break;
            case 1:
                TEST_REMOTE_PATH = path; break;
            case 2:
                SIMULATE_REMOTE_PATH = path; break;
            case 3:
                LOCAL_PATH = path; break;
            default:
                break;
        }
    }
    public void Init()
    {
        //InitPath
        InitPath();
        //InitResFloder
        string localPathBundles = Path.Combine(Application.persistentDataPath, BUNDLES_FOLDERNAME);
        string localPathConfigTables = Path.Combine(Application.persistentDataPath, CONFIG_FOLDERNAME);
        string localPathScripts = Path.Combine(Application.persistentDataPath, SCRIPT_FOLDERNAME);
        
        if (!Directory.Exists(localPathBundles)) Directory.CreateDirectory(localPathBundles);
        if (!Directory.Exists(localPathConfigTables)) Directory.CreateDirectory(localPathConfigTables);
        if (!Directory.Exists(localPathScripts)) Directory.CreateDirectory(localPathScripts);
        //InitBundlesDic
        bundles = new Dictionary<string, AssetBundle>();
    }

    /// <summary>
    /// ��Զ��SCRIPT_FOLDERNAME�ļ��е����ݣ�����������ɳ���ļ���
    /// </summary>
    /// <param name="fileNames">�ļ���</param>
    /// <returns></returns>
    public IEnumerator DownloadScripts(params string[] fileNames)
    {
        if (fileNames != null)
        {
            foreach (string file in fileNames)
            {
                string n = Path.Combine(SCRIPT_FOLDERNAME, Path.GetFileName(file));
                if (!n.EndsWith(".meta")) yield return StartCoroutine(CopyRemoteFile(n));
            }
        }
    }
    /// <summary>
    /// ��Զ��CONFIG_FOLDERNAME�ļ��е����ݣ�����������ɳ���ļ���
    /// </summary>
    /// <param name="fileNames">�ļ���</param>
    /// <returns></returns>
    public IEnumerator DownloadTables(params string[] fileNames)
    {

        if (fileNames != null)
        {
            foreach (string file in fileNames)
            {
                Debug.Log(Path.GetFileName(file));
                string n = Path.Combine(CONFIG_FOLDERNAME, Path.GetFileName(file));
                if (!n.EndsWith(".meta")) yield return StartCoroutine(CopyRemoteFile(n));
            }
        }
    }
    /// <summary>
    /// ��Զ�ˡ�BUNDLES_FOLDERNAME���ļ������AB�ļ����ص����أ���װ�ص�bundles
    /// </summary>
    /// <param name="bundleNames">AB���ļ���</param>
    /// <returns></returns>
    public IEnumerator DownloadBundles(params string[] bundleNames)
    {
        if (bundleNames != null)
        {
            foreach (string file in bundleNames)
            {
                yield return DownloadBundle(file);
            }
        }
    }
    /// <summary>
    /// ��Զ�ˡ�BUNDLES_FLODERNAME���ļ������AB�ļ����ص����أ���װ�ص�bundles
    /// </summary>
    /// <param name="bundleName">�ļ���</param>
    /// <returns></returns>
    public IEnumerator DownloadBundle(string bundleName)
    {
        Debug.Log($"downloading: {bundleName}");
        string path = Path.Combine(BUNDLES_FOLDERNAME, bundleName);
        //�Ա�Զ���ļ�������
        yield return StartCoroutine(CompareFile($"{path}.manifest", (a) =>
        {
            return DownloadBundle(path, a);
        }));
        yield return LoadAndRefBundle(bundleName);
    }
    /// <summary>
    /// ��ָ���ļ����ݰ��ָ���ת�����ļ���
    /// </summary>
    /// <param name="splitChar">�ָ���</param>
    /// <param name="filepath">�ļ�·��</param>
    /// <param name="fileContent">ת����ı�������</param>
    /// <returns></returns>
    IEnumerator ReadTableFileHead(char splitChar, string filepath, List<string> fileContent)
    {

        // ��ȡStreamingAssets�ļ��е�·��
        //string filepath = System.IO.Path.Combine(Application.streamingAssetsPath, "dl.txt");

        // ʹ��UnityWebRequest�����ļ�
        UnityWebRequest request = UnityWebRequest.Get(filepath);

        // ��������
        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            // �ɹ���ȡ�ļ�����
            string file = request.downloadHandler.text;
            fileContent.AddRange(file.Split(splitChar));
        }
        else
        {
            // ��ȡʧ��
            Debug.LogError($"failed to load file:{filepath}\n" + request.error);
        }

        // �ͷ�����
        request.Dispose();
    }
    IEnumerator CompareFile(string subpath)
    {
        yield return StartCoroutine(CompareFile($"{subpath}.manifest", (a) =>
        {
            return DownloadBundle(subpath, a);
        }));
    }
    IEnumerator DownloadBundle(string name, bool isSame)
    {
        yield return null;
        if (!isSame)
        {
            Debug.LogError($"file:{name} needs to be downloaded");
            yield return StartCoroutine(CopyRemoteFile(name));
            yield return StartCoroutine(CopyRemoteFile($"{name}.manifest"));
        }
        else
        {
            Debug.LogError($"file:{name} is does not need to be updated ");
        }
    }
    IEnumerator LoadAndRefBundle(string name)
    {
        if (bundles.ContainsKey(name) && bundles[name] != null)
        {
            bundles[name].Unload(false);
        }
        yield return StartCoroutine(LoadAssetBundleLocal(name, (a) =>
        {
            bundles[name] = a;
        }));
    }
    IEnumerator CompareFile(string subPath, System.Func<bool, IEnumerator> onCompare)
    {

        string remoteUrl = "";
        switch (assetsDownloadEnv)
        {
            case AssetsDownloadEnv.Simulation:
                remoteUrl = SIMULATE_REMOTE_PATH;
                break;
            case AssetsDownloadEnv.Testing:
                remoteUrl = TEST_REMOTE_PATH;
                break;
            case AssetsDownloadEnv.Production:
                remoteUrl = REMOTE_PATH;
                break;
        }
        remoteUrl = Path.Combine(remoteUrl, subPath);
        string localUrl = Path.Combine(LOCAL_PATH, subPath);



        bool result = false;
        bool isRmote = false, isLocal = false;
        string remoteText = "a", localText = "b";
        // ʹ��UnityWebRequest����AssetBundle
        UnityWebRequest request = UnityWebRequest.Get(remoteUrl);
        // ��������
        yield return request.SendWebRequest();
        // �������Ƿ�ɹ�
        if (request.result == UnityWebRequest.Result.Success)
        {
            isRmote = true;
            remoteText = request.downloadHandler.text;
        }

        if (File.Exists(localUrl))
        {
            isLocal = true;
            localText = File.ReadAllText(localUrl);
        }

        if (isRmote && isLocal)
        {
            result = (remoteText == localText);
        }

        yield return onCompare.Invoke(result);
    }
    IEnumerator CopyRemoteFile(string subPath)
    {
        string remoteUrl = "";
        switch (assetsDownloadEnv)
        {
            case AssetsDownloadEnv.Simulation:
                remoteUrl = SIMULATE_REMOTE_PATH;
                break;
            case AssetsDownloadEnv.Testing:
                remoteUrl = TEST_REMOTE_PATH;
                break;
            case AssetsDownloadEnv.Production:
                remoteUrl = REMOTE_PATH;
                break;
        }
        remoteUrl = Path.Combine(remoteUrl, subPath);

        string localUrl = Path.Combine(LOCAL_PATH, subPath);
        Debug.Log(localUrl);
        UnityWebRequest request = UnityWebRequest.Get(remoteUrl);
        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            try
            {
                File.WriteAllBytes(localUrl, request.downloadHandler.data);
                Debug.Log("remotefile saved to: " + localUrl);
            }
            catch (System.Exception e)
            {
                Debug.LogError($"file saved failed:{subPath}\n" + e.Message);
            }
        }
        else
        {
            Debug.LogError($"failed to load remote file:{subPath}\n" + request.error);
        }
    }
    
    IEnumerator LoadAssetBundleLocal(string assetBundleName, System.Action<AssetBundle> onComplete)
    {
        string headPath = LOCAL_PATH;
        headPath = Path.Combine(headPath, BUNDLES_FOLDERNAME);
        string assetBundlePath = Path.Combine(headPath, assetBundleName);
        yield return null;

        var bundle = AssetBundle.LoadFromFileAsync(assetBundlePath);

        while (!bundle.isDone)
        {
            yield return null;
            Debug.Log(bundle.progress);
        }

        if (bundle == null)
        {
            Debug.LogError("failed to get assetBundle content");
        }
        else
        {
            onComplete.Invoke(bundle.assetBundle);
            Debug.Log("load complate");
        }
    }

    public class Debug
    {
        public static void LogError(object s)
        {
            //UnityEngine.Debug.LogError(s);
        }
        public static void Log(object s)
        {
            //UnityEngine.Debug.Log(s);
        }
    }


    /// <summary>
    /// ���ָ����Bundle
    /// </summary>
    public void ClearBundles(string name)
    {
        if (bundles != null&&bundles.ContainsKey(name)&& bundles[name]!=null)
        {
            bundles[name].Unload(true);
            bundles.Remove(name);
        }
    }
}

public enum AssetsDownloadEnv
{
    Simulation, // ģ�⻷��
    Testing,    // ���Ի���
    Production  // ��ʽ����
}